package com.zhiyou100.service.impl;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Validator;
import cn.hutool.crypto.SecureUtil;
import com.github.tobato.fastdfs.FastDFSClient;
import com.zhiyou100.entity.TabDirectory;
import com.zhiyou100.entity.TabFile;
import com.zhiyou100.exception.DirectoryException;
import com.zhiyou100.mapper.TabDirectoryMapper;
import com.zhiyou100.mapper.TabFileMapper;
import com.zhiyou100.service.ITabDirectoryService;
import com.zhiyou100.service.ITabFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhiyou100.util.file.FileUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.File;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 杨磊
 * @since 2020-10-09
 */
@Slf4j
@Service
public class TabFileServiceImpl extends ServiceImpl<TabFileMapper, TabFile> implements ITabFileService {

    @Autowired
    private FastDFSClient client;
    @Autowired
    private TabFileMapper fileMapper;
    @Autowired
    private ITabDirectoryService directoryMapper;
    @Autowired
    private TabDirectoryMapper directoryMap;

    /**
     * java.lang.IllegalStateException: File has been moved - cannot be read again。
     * multipartFile 转换为 file，通过 new FileInputStream (file) 获取 InputStream
     *
     * @param directory 要添加的文件
     * @param file      文件对象
     */
    @SneakyThrows
    @Override
    public void addOne(TabDirectory directory, MultipartFile file) {
        // MultipartFile to File
        final File toFile = FileUtil.toFile(file);
        // 读取文件
        final FileReader fileReader = new FileReader(toFile);
        // 获取输出流
        final BufferedInputStream inputStream = fileReader.getInputStream();

        // 1 先判断当前目录下是否用同名的文件夹｜文件
        final TabDirectory tabDirectory = directoryMapper.selectByDfuAndUidAndDname(directory);
        log.debug("directoryMapper.selectByDfuAndUidAndDname(directory) = {}", tabDirectory);
        if (Validator.isNotNull(tabDirectory)) {
            log.debug(" 文件已经存在 ！");
            throw new DirectoryException("文件夹已存在！");
        }
        // 记录文件
        TabFile tabFile = null;

        // 2 判断文件是否存在
        // 获取 fmd5 值
        final String fmd5 = SecureUtil.md5(inputStream);
        log.debug("fmd5 = {}", fmd5);
        // 判断 fmd5 值是否存在
        tabFile = selectOneByFmd5(fmd5);
        log.debug("tabFile = selectOneByFmd5(fmd5) = {}", tabFile);
        if (Validator.isNull(tabFile)) {
            log.debug("tabFile == null ");
            // 文件不存在，则上传文件服务器
            // 获取上传后的路径 e.g. group1/M00/00/00/wKjZlV-JC_OAA0qXAC6kQid9k8Q854.jpg
            final String upload = client.upload(toFile);
            log.debug(" 上传后的路径 {}", upload);
            // 保存 file 对象
            tabFile = TabFile.builder()
                    .fmd5(fmd5)
                    .furl(upload)
                    .fsize(file.getSize() + "")
                    .build();
            // 保存文件
            fileMapper.insert(tabFile);
            // 根据 fmd5 获取 文件
            tabFile = selectOneByFmd5(fmd5);
        }
        // 3 添加 Directory
        assert tabFile != null;
        directory.setFid(tabFile.getFid());
        // 设置创建时间
        directory.setDcreateTime(LocalDateTime.now());
        // 指定是文件
        directory.setDtype(1);
        // 添加文件夹
        directoryMapper.save(directory);
    }

    @Override
    public TabFile selectOneByFmd5(String fmd5) {
        final List<TabFile> fmd51 = fileMapper.selectByMap(Dict.create().set("fmd5", fmd5));
        if (fmd51.isEmpty()) {
            return null;
        }
        return fmd51.get(0);
    }

    @Override
    public TabFile selectOneByDid(Integer did) {
        final TabDirectory byId = directoryMapper.getById(did);
        return fileMapper.selectById(byId.getFid());
    }

    @Override
    public TabDirectory selectOnByFid(Integer fid) {
        final Dict fidMap = Dict.create()
                .set("fid", fid);
        return directoryMap.selectByMap(fidMap).get(0);
    }
}
